<?php

/*
*	$version: 2007-12-29 16:15:03 beta 1.0
*	$id: captcha.php
*	$author: taoFeng
*	$mailto: font99@Gmail.com
*	$license: This is not a freeware
*/

if (!defined('IN_LEKO')) {header("HTTP/1.0 403 Forbidden");exit;}

class Captcha
{
		public $TTF_folder;
		public $minchars = 5;

		public $maxchars = 7;
		public $minsize = 20;
		public $maxsize = 30;
		public $maxrotation = 25;
		public $noise = true;
		public $websafecolors = true;
		public $debug = false;

		public $case_sensitive = false;//大小写是否敏感
		public $validchars = 'abcdefghkmnpqrstuvwxy23456789ABCDEFGHKMNPQRSTUVWXY23456789';
		public $lx;
		public $ly;
		public $jpegquality = 80;
		public $noisefactor = 9;
		public $nb_noise;
		public $TTF_RANGE;
		public $TTF_file;

		public $chars;
	
		public $public_K;
		public $private_K;
		public $gd_version;
	
		public $r;
		public $g;
		public $b;
		public $imgtype = 'png';
		public $session = 'authCode';

		function captcha($config,$secure=TRUE)
		{

			// 测试gd库
			$this->gd_version = $this->get_gd_version();
			if($this->gd_version == 0) die('There is no GD-Library-Support enabled. The captcha class cannot be used!');
			if($this->debug) echo "\n<br>-Captcha-Debug: The available GD-Library has major version ".$this->gd_version;

			// extracts config array
			if(is_array($config))
			{
				if($secure && (!function_exists('version_compare') || version_compare(phpversion(), '4.2.0', '< ')) && function_exists(array_key_exists))
				{
					if($this->debug) echo "\n<br>-good8-Captcha-Debug: Extracts Config-Array in secure-mode!";
					$valid = get_class_vars(get_class($this));
					foreach($config as $k=>$v)
					{
						if(array_key_exists($k,$valid)) $this->$k = $v;
					}
				}
				else
				{
					if($this->debug) echo "\n<br>-good8-Captcha-Debug: Extracts Config-Array in unsecure-mode!";
					foreach($config as $k=>$v) $this->$k = $v;
				}
			}

			// 检查最大最小字符
			if($this->minchars > $this->maxchars)
			{
				$temp = $this->minchars;
				$this->minchars = $this->maxchars;
				$this->maxchars = $temp;
				if($this->debug) echo "\n<br>-Captcha-Debug: Arrghh! What do you think I mean with min and max? Switch minchars with maxchars.";
			}
			if($this->minsize > $this->maxsize)
			{
				$temp = $this->minsize;
				$this->minsize = $this->maxsize;
				$this->maxsize = $temp;
				if($this->debug) echo "\n<br>-Captcha-Debug: Arrghh! What do you think I mean with min and max? Switch minsize with maxsize.";
			}


			// check TrueTypeFonts

			$this->TTF_RANGE = array('0');
			
				if ($handle = opendir($this->TTF_folder)) {
				$i=0;

				while (false !== ($file = readdir($handle))) {
		
				//检查所有字体文件

					if ($file != '.' && $file != '..') {
					
				$this->TTF_RANGE[$i]=$file;
				
				if($this->debug) echo "\n<br>-Captcha-Debug: Found font file (".$file.')';
				
					}

				}

				closedir($handle);
			}
			if(is_array($this->TTF_RANGE))
			{
				if($this->debug) echo "\n<br>-Captcha-Debug: Checking given TrueType-Array! (".count($this->TTF_RANGE).')';
				$temp = array();
				foreach($this->TTF_RANGE as $k=>$v)
				{
					if(is_readable($this->TTF_folder.$v)) $temp[] = $v;
				}
				$this->TTF_RANGE = $temp;
				if($this->debug) echo "\n<br>-Captcha-Debug: Valid TrueType-files: (".count($this->TTF_RANGE).')';
				if(count($this->TTF_RANGE) < 1) die('No Truetype fonts available for the CaptchaClass.');
			}
			else
			{
				if($this->debug) echo "\n<br>-Captcha-Debug: Check given TrueType-File! (".$this->TTF_RANGE.')';
				if(!is_readable($this->TTF_folder.$this->TTF_RANGE)) die('No Truetypefont available for the good8 captcha class.');
			}
			
			// 选择第一个字体
			$this->change_TTF();
			if($this->debug) echo "\n<br>-Captcha-Debug: Set current TrueType-File: (".$this->TTF_file.")";

			//干扰字符的是否是设置为背景
			$this->nb_noise = $this->noise ? ($this->chars * $this->noisefactor) : 0;
			if($this->debug) echo "\n<br>-Captcha-Debug: Set number of noise characters to: (".$this->nb_noise.')';

			// 随机种子

			if( !function_exists('version_compare') || version_compare(phpversion(), '4.2.0', '< ') )
			{
				mt_srand((double)microtime()*1000000);
			}

			if($this->debug) echo "\n<br>-Captcha-Debug: The counterfilename is (".$this->tempfolder.$this->counter_filename.')';

		}

		////////////////////////////////
		//
		//	PUBLIC METHODS
		//

		/**
		  * 生成图片
		  *
		  **/
		function get_good8_captcha()
		{
			echo $this->make_captcha();

		}

		/**
		  * 获取图象类型
		  *
		  **/
		 
		function get_good8_imagetype($extension) 
		{
			switch (strtolower($extension)) 
			{
				case 'png':
					$information['mime'] = image_type_to_mime_type(IMAGETYPE_PNG);
					$information['func'] = 'imagepng';
					break;
				case 'gif':
					$information['mime'] = image_type_to_mime_type(IMAGETYPE_GIF);
					$information['func'] = 'imagegif';
					break;
				case 'wbmp':
					$information['mime'] = image_type_to_mime_type(IMAGETYPE_WBMP);
					$information['func'] = 'imagewbmp';
					break;
				case 'jpg':
				case 'jpeg':
				case 'jpe':
					$information['mime'] = image_type_to_mime_type(IMAGETYPE_JPEG);
					$information['func'] = 'imagejpeg';
					break;
				default:
					$information = false;
			}
			return $information;
		}
		

		/**
		  *　验证结果
		  * 
		  * Returns 0 = invalid sumbit | 1 = valid submit
		  *
		  **/
		function validate_submit($image,$attempt)
		{
			$correct_hash = substr($image,-36,32);

			if($this->case_sensitive==0) $attempt = strtoupper($attempt);//是否区分大小写
			
			if($this->check_captcha($correct_hash,$attempt))
			{
				if($this->debug) echo "\n<br>-Captcha-Debug: Validating submitted form returns: (1)";
				return 1;
			}
			else
			{
				if($this->debug) echo "\n<br>-Captcha-Debug: Validating submitted form returns: (0)";
				return 0;
			}
		}

		////////////////////////////////
		//
		//	私有方法
		//
		function make_captcha($private_key='')
		{
			
			// 设置图片大小
			if($private_key=='') $private_key = $this->generate_keypair();

			$this->lx = (strlen($private_key) + 1) * (int)(($this->maxsize + $this->minsize) / 1.5);
			$this->ly = (int)(2.4 * $this->maxsize);
			if($this->debug) echo "\n<br>-Captcha-Debug: Set image dimension to: (".$this->lx.' x '.$this->ly.')';
			if($this->debug) echo "\n<br>-Captcha-Debug: Generate private key: ($private_key)";

			$this->nb_noise = $this->noise ? (strlen($private_key) * $this->noisefactor) : 0;
			if($this->debug) echo "\n<br>-Captcha-Debug: Set number of noise characters to: (".$this->nb_noise.')';

			//创建图片
			if($this->gd_version >= 2 && !$this->websafecolors)
			{
				$func1 = 'imagecreatetruecolor';
				$func2 = 'imagecolorallocate';
			}
			else
			{
				$func1 = 'imageCreate';
				$func2 = 'imagecolorclosest';
			}
			$image = $func1($this->lx,$this->ly);
			if($this->debug) echo "\n<br>-Captcha-Debug: Generate ImageStream with: ($func1())";
			if($this->debug) echo "\n<br>-Captcha-Debug: For colordefinitions we use: ($func2())";
			$information = $this->get_good8_imagetype($this->imgtype);
			
			// 设置背景颜色
			//$this->random_color(224, 255);
			$this->random_color(255, 255);
			$back =  @imagecolorallocate($image, $this->r, $this->g, $this->b);
			@ImageFilledRectangle($image,0,0,$this->lx,$this->ly,$back);
			if($this->debug) echo "\n<br>-Captcha-Debug: We allocate one color for Background: (".$this->r.'-'.$this->g.'-'.$this->b.')';

			//分配网页安全色到图片
			if($this->gd_version < 2 || $this->websafecolors) $this->makeWebsafeColors($image);

			//填写干扰码或者格子
			if($this->nb_noise > 0)
			{
				//随机字符为背景包括随机角度，随机颜色，随机位置
				if($this->debug) echo "\n<br>-Captcha-Debug: Fill background with noise: (".$this->nb_noise.')';
				for($i=0; $i < $this->nb_noise; $i++)
				{
					$size	= intval(mt_rand((int)($this->minsize / 2.3), (int)($this->maxsize / 1.7)));
					$angle	= intval(mt_rand(0, 360));
					$x		= intval(mt_rand(0, $this->lx));
					$y		= intval(mt_rand(0, (int)($this->ly - ($size / 5))));
					$this->random_color(160, 224);
					$color	= $func2($image, $this->r, $this->g, $this->b);
					$text	= chr(intval(mt_rand(45,250)));
					@ImageTTFText($image, $size, $angle, $x, $y, $color, $this->change_TTF(), $text);
				}
			}
			else
			{
				//生成格子
				if($this->debug) echo "\n<br>-Captcha-Debug: Fill background with x-gridlines: (".(int)($this->lx / (int)($this->minsize / 1.5)).')';
				for($i=0; $i < $this->lx; $i += (int)($this->minsize / 1.5))
				{
					$this->random_color(160, 224);
					$color	= $func2($image, $this->r, $this->g, $this->b);
					@imageline($image, $i, 0, $i, $this->ly, $color);
				}
				if($this->debug) echo "\n<br>-Captcha-Debug: Fill background with y-gridlines: (".(int)($this->ly / (int)(($this->minsize / 1.8))).')';
				for($i=0 ; $i < $this->ly; $i += (int)($this->minsize / 1.8))
				{
					$this->random_color(160, 224);
					$color	= $func2($image, $this->r, $this->g, $this->b);
					@imageline($image, 0, $i, $this->lx, $i, $color);
				}
			}

			// 写入字
			if($this->debug) echo "\n<br>-Captcha-Debug: Fill forground with chars and shadows: (".$this->chars.')';
			for($i=0, $x = intval(mt_rand($this->minsize,$this->maxsize)); $i < strlen($private_key); $i++)
			{
				$text	= substr($private_key, $i, 1);
				$angle	= intval(mt_rand(($this->maxrotation * -1), $this->maxrotation));
				$size	= intval(mt_rand($this->minsize, $this->maxsize));
				$y		= intval(mt_rand((int)($size * 1.5), (int)($this->ly - ($size / 7))));
				$this->random_color(0, 127);
				$color	=  $func2($image, $this->r, $this->g, $this->b);
				$this->random_color(0, 127);
				$shadow = $func2($image, $this->r + 127, $this->g + 127, $this->b + 127);
				@ImageTTFText($image, $size, $angle, $x + (int)($size / 15), $y, $shadow, $this->change_TTF(), $text);
				@ImageTTFText($image, $size, $angle, $x, $y - (int)($size / 15), $color, $this->TTF_file, $text);
				$x += (int)($size + ($this->minsize / 5));
			}
			//@ImageJPEG($image, $this->get_filename(), $this->jpegquality);
            header("Cache-Control: no-cache, must-revalidate");
            header("Content-type: ".$information['mime']);
			@$information['func']($image);
			$res = file_exists($this->get_filename());
			if($this->debug) echo "\n<br>-Captcha-Debug: Save Image with quality [".$this->jpegquality.'] as ('.$this->get_filename().') returns: ('.($res ? 'TRUE' : 'FALSE').')';
			@ImageDestroy($image);
			if($this->debug) echo "\n<br>-Captcha-Debug: Destroy Imagestream.";
			if(!$res) die('Unable to save captcha-image.');
		}

		/** @private **/
		function makeWebsafeColors(&$image)
		{
			for($r = 0; $r <= 255; $r += 51)
			{
				for($g = 0; $g <= 255; $g += 51)
				{
					for($b = 0; $b <= 255; $b += 51)
					{
						$color = imagecolorallocate($image, $r, $g, $b);
					}
				}
			}
			if($this->debug) echo "\n<br>-Captcha-Debug: Allocate 216 websafe colors to image: (".imagecolorstotal($image).')';
		}

		/** @private **/
		function random_color($min,$max)
		{
			$this->r = intval(mt_rand($min,$max));
			$this->g = intval(mt_rand($min,$max));
			$this->b = intval(mt_rand($min,$max));
		}

		/** @private **/
		function change_TTF()
		{
			if(is_array($this->TTF_RANGE))
			{
				$key = array_rand($this->TTF_RANGE);
				$this->TTF_file = $this->TTF_folder.$this->TTF_RANGE[$key];
			}
			else
			{
				$this->TTF_file = $this->TTF_folder.$this->TTF_RANGE;
			}
			return $this->TTF_file;
		}

		/** @private **/
		function get_gd_version()
		{
			if (!function_exists('imagejpeg')) {
			   $gd_version_number = 0;
			} else {
				static $gd_version_number = null;
				if($gd_version_number === null)
				{
				   ob_start();
				   phpinfo(8);
				   $module_info = ob_get_contents();
				   ob_end_clean();
				   if(preg_match("/\bgd\s+version\b[^\d\n\r]+?([\d\.]+)/i", $module_info, $matches))
				   {
					   $gd_version_number = $matches[1];
				   }
				   else
				   {
					   $gd_version_number = 0;
				   }
				}
			}
			return $gd_version_number;
		}

		function generate_keypair()//获取验证码
		{

			// 初始化 session
			// 如果 session 未启用, 则开启它
			if (empty($_SESSION[session_id()])) @session_start();

			
			$this->chars = mt_rand($this->minchars,$this->maxchars);
			for($i=0; $i < $this->chars; $i++) {
				$key .= $this->validchars{mt_rand(0,strlen($this->validchars)-1)};
			}
			
			if($this->case_sensitive==0)
			{
				$key = strtolower($key);
				$this->public_key = md5($key);
				$_SESSION[$this->session.'_none_case'] = $this->public_key;
			}
			else
			{
				$this->public_key = md5($key);
				$_SESSION[$this->session] = $this->public_key;
			}
			
			if($this->debug) echo "\n<br>-Captcha-Debug: Generate Keys, private key is: (".$key.')';
			if($this->debug) echo "\n<br>-Captcha-Debug: Generate Keys, public key is: (".$this->public_key.')';

			return $key;
		}
} // END CLASS good8_captcha

/*
$TTF_folder = './resource/font/';

$minchars = 5;

$maxchars = 5;

$minsize = 15;

$maxsize = 15;

$maxrotation = 25;

$noise = TRUE;

$websafecolors = FALSE;

$debug = FALSE;

$case_sensitive = FALSE;

$folder_root = '.';

$imgtype = 'png';

$CAPTCHA_CONFIG = array('TTF_folder'=>$folder_root.'/'.$TTF_folder,'minchars'=>$minchars,'maxchars'=>$maxchars,'minsize'=>$minsize,'maxsize'=>$maxsize,'maxrotation'=>$maxrotation,'noise'=>$noise,'websafecolors'=>$websafecolors,'debug'=>$debug,'case_sensitive'=>$case_sensitive,'imgtype'=>$imgtype);

$captcha =& new captcha($CAPTCHA_CONFIG);
echo $imgLoc = $captcha->get_good8_captcha();
*/
?>
